﻿// Decompiled with JetBrains decompiler
// Type: TaleWorlds.MountAndBlade.View.Tableaus.ItemTableau
// Assembly: TaleWorlds.MountAndBlade.View, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 61152EB8-513B-4D4A-8AC0-0D1465C6CF6C
// Assembly location: D:\steam\steamapps\common\Mount & Blade II Bannerlord\Modules\Native\bin\Win64_Shipping_Client\TaleWorlds.MountAndBlade.View.dll

using System;
using System.Linq;
using TaleWorlds.Core;
using TaleWorlds.DotNet;
using TaleWorlds.Engine;
using TaleWorlds.Engine.Options;
using TaleWorlds.InputSystem;
using TaleWorlds.Library;
using TaleWorlds.ObjectSystem;

#nullable disable
namespace TaleWorlds.MountAndBlade.View.Tableaus
{
  public class ItemTableau
  {
    private Scene _tableauScene;
    private GameEntity _itemTableauEntity;
    private MatrixFrame _itemTableauFrame = MatrixFrame.Identity;
    private bool _isRotating;
    private bool _isTranslating;
    private bool _isRotatingByDefault;
    private bool _initialized;
    private int _tableauSizeX;
    private int _tableauSizeY;
    private float _cameraRatio;
    private Camera _camera;
    private Vec3 _midPoint;
    private const float InitialCamFov = 1f;
    private float _curZoomSpeed;
    private Vec3 _curCamDisplacement = Vec3.Zero;
    private bool _isEnabled;
    private float _panRotation;
    private float _tiltRotation;
    private bool _hasInitialTiltRotation;
    private float _initialTiltRotation;
    private bool _hasInitialPanRotation;
    private float _initialPanRotation;
    private float RenderScale = 1f;
    private string _stringId = "";
    private int _ammo;
    private int _averageUnitCost;
    private string _itemModifierId = "";
    private string _bannerCode = "";
    private ItemRosterElement _itemRosterElement;
    private MatrixFrame _initialFrame;
    private bool _lockMouse;

    public Texture Texture { get; private set; }

    private TableauView View
    {
      get
      {
        return (NativeObject) this.Texture != (NativeObject) null ? this.Texture.TableauView : (TableauView) null;
      }
    }

    private bool _isSizeValid => this._tableauSizeX > 0 && this._tableauSizeY > 0;

    public ItemTableau() => this.SetEnabled(true);

    public void SetTargetSize(int width, int height)
    {
      int num = this._isSizeValid ? 1 : 0;
      this._isRotating = false;
      if (width <= 0 || height <= 0)
      {
        this._tableauSizeX = 10;
        this._tableauSizeY = 10;
      }
      else
      {
        this.RenderScale = NativeOptions.GetConfig(NativeOptions.NativeOptionsType.ResolutionScale) / 100f;
        this._tableauSizeX = (int) ((double) width * (double) this.RenderScale);
        this._tableauSizeY = (int) ((double) height * (double) this.RenderScale);
      }
      this._cameraRatio = (float) this._tableauSizeX / (float) this._tableauSizeY;
      this.View?.SetEnable(false);
      this.View?.AddClearTask(true);
      this.Texture?.ReleaseNextFrame();
      if (num == 0 && this._isSizeValid)
        this.Recalculate();
      this.Texture = TableauView.AddTableau(nameof (ItemTableau), new RenderTargetComponent.TextureUpdateEventHandler(this.TableauMaterialTabInventoryItemTooltipOnRender), (object) this._tableauScene, this._tableauSizeX, this._tableauSizeY);
    }

    public void OnFinalize()
    {
      this.View?.SetEnable(false);
      this._camera?.ReleaseCameraEntity();
      this._camera = (Camera) null;
      this.View?.AddClearTask();
      this._tableauScene = (Scene) null;
      this.Texture = (Texture) null;
      this._initialized = false;
      if (!this._lockMouse)
        return;
      this.UpdateMouseLock(true);
    }

    protected void SetEnabled(bool enabled)
    {
      this._isRotatingByDefault = true;
      this._isRotating = false;
      this.ResetCamera();
      this._isEnabled = enabled;
      TableauView view = this.View;
      if (!((NativeObject) view != (NativeObject) null))
        return;
      view.SetEnable(this._isEnabled);
    }

    public void SetStringId(string stringId)
    {
      this._stringId = stringId;
      this.Recalculate();
    }

    public void SetAmmo(int ammo)
    {
      this._ammo = ammo;
      this.Recalculate();
    }

    public void SetAverageUnitCost(int averageUnitCost)
    {
      this._averageUnitCost = averageUnitCost;
      this.Recalculate();
    }

    public void SetItemModifierId(string itemModifierId)
    {
      this._itemModifierId = itemModifierId;
      this.Recalculate();
    }

    public void SetBannerCode(string bannerCode)
    {
      this._bannerCode = bannerCode;
      this.Recalculate();
    }

    public void Recalculate()
    {
      if (UiStringHelper.IsStringNoneOrEmptyForUi(this._stringId) || !this._isSizeValid)
        return;
      ItemModifier itemModifier = (ItemModifier) null;
      ItemObject itemObject = MBObjectManager.Instance.GetObject<ItemObject>(this._stringId) ?? Game.Current.ObjectManager.GetObjectTypeList<ItemObject>().FirstOrDefault<ItemObject>((Func<ItemObject, bool>) (item => item.IsCraftedWeapon && item.WeaponDesign.HashedCode == this._stringId));
      if (!string.IsNullOrEmpty(this._itemModifierId))
        itemModifier = MBObjectManager.Instance.GetObject<ItemModifier>(this._itemModifierId);
      if (itemObject == null)
        return;
      this._itemRosterElement = new ItemRosterElement(itemObject, this._ammo, itemModifier);
      this.RefreshItemTableau();
      if ((NativeObject) this._itemTableauEntity != (NativeObject) null)
      {
        float num1 = Screen.RealScreenResolutionWidth / (float) this._tableauSizeX;
        float num2 = Screen.RealScreenResolutionHeight / (float) this._tableauSizeY;
        float num3 = (double) num1 > (double) num2 ? num1 : num2;
        if ((double) num3 < 1.0)
        {
          Vec3 globalBoxMax = this._itemTableauEntity.GlobalBoxMax;
          Vec3 globalBoxMin = this._itemTableauEntity.GlobalBoxMin;
          this._itemTableauFrame = this._itemTableauEntity.GetFrame();
          float length = this._itemTableauFrame.rotation.f.Length;
          this._itemTableauFrame.rotation.Orthonormalize();
          this._itemTableauFrame.rotation.ApplyScaleLocal(length * num3);
          this._itemTableauEntity.SetFrame(ref this._itemTableauFrame);
          if (globalBoxMax.NearlyEquals(this._itemTableauEntity.GlobalBoxMax) && globalBoxMin.NearlyEquals(this._itemTableauEntity.GlobalBoxMin))
          {
            this._itemTableauEntity.SetBoundingboxDirty();
            this._itemTableauEntity.RecomputeBoundingBox();
          }
          this._itemTableauFrame.origin += (globalBoxMax + globalBoxMin - this._itemTableauEntity.GlobalBoxMax - this._itemTableauEntity.GlobalBoxMin) * 0.5f;
          this._itemTableauEntity.SetFrame(ref this._itemTableauFrame);
          this._midPoint = (this._itemTableauEntity.GlobalBoxMax + this._itemTableauEntity.GlobalBoxMin) * 0.5f + (globalBoxMax + globalBoxMin - this._itemTableauEntity.GlobalBoxMax - this._itemTableauEntity.GlobalBoxMin) * 0.5f;
        }
        else
          this._midPoint = (this._itemTableauEntity.GlobalBoxMax + this._itemTableauEntity.GlobalBoxMin) * 0.5f;
        if (this._itemRosterElement.EquipmentElement.Item.ItemType == ItemObject.ItemTypeEnum.HandArmor || this._itemRosterElement.EquipmentElement.Item.ItemType == ItemObject.ItemTypeEnum.Shield)
          this._midPoint *= 1.2f;
        this.ResetCamera();
      }
      this._isRotatingByDefault = true;
      this._isRotating = false;
    }

    public void Initialize()
    {
      this._isRotatingByDefault = true;
      this._isRotating = false;
      this._isTranslating = false;
      this._tableauScene = Scene.CreateNewScene();
      this._tableauScene.SetName(nameof (ItemTableau));
      this._tableauScene.DisableStaticShadows(true);
      this._tableauScene.SetAtmosphereWithName("character_menu_a");
      Vec3 direction = new Vec3(1f, -1f, -1f);
      this._tableauScene.SetSunDirection(ref direction);
      this._tableauScene.SetClothSimulationState(false);
      this.ResetCamera();
      this._initialized = true;
    }

    private void TranslateCamera(bool value) => this.TranslateCameraAux(value);

    private void TranslateCameraAux(bool value)
    {
      this._isRotatingByDefault = !value && this._isRotatingByDefault;
      this._isTranslating = value;
      this.UpdateMouseLock();
    }

    private void ResetCamera()
    {
      this._curCamDisplacement = Vec3.Zero;
      this._curZoomSpeed = 0.0f;
      if (!((NativeObject) this._camera != (NativeObject) null))
        return;
      this._camera.Frame = MatrixFrame.Identity;
      this.SetCamFovHorizontal(1f);
      this.MakeCameraLookMidPoint();
    }

    public void RotateItem(bool value)
    {
      this._isRotatingByDefault = !value && this._isRotatingByDefault;
      this._isRotating = value;
      this.UpdateMouseLock();
    }

    public void RotateItemVerticalWithAmount(float value) => this.UpdateRotation(0.0f, value / -2f);

    public void RotateItemHorizontalWithAmount(float value)
    {
      this.UpdateRotation(value / 2f, 0.0f);
    }

    public void OnTick(float dt)
    {
      float num1 = Input.MouseMoveX + Input.GetKeyState(InputKey.ControllerLStick).X * 1000f * dt;
      float num2 = Input.MouseMoveY + Input.GetKeyState(InputKey.ControllerLStick).Y * -1000f * dt;
      if (this._isEnabled && (this._isRotating || this._isTranslating) && (!num1.ApproximatelyEqualsTo(0.0f) || !num2.ApproximatelyEqualsTo(0.0f)))
      {
        if (this._isRotating)
          this.UpdateRotation(num1, num2);
        if (this._isTranslating)
          this.UpdatePosition(num1, num2);
      }
      this.TickCameraZoom(dt);
    }

    private void UpdatePosition(float mouseMoveX, float mouseMoveY)
    {
      if (!this._initialized)
        return;
      this._curCamDisplacement += new Vec3(mouseMoveX / (float) -this._tableauSizeX, mouseMoveY / (float) this._tableauSizeY) * (2.2f * this._camera.HorizontalFov);
      this.MakeCameraLookMidPoint();
    }

    private void UpdateRotation(float mouseMoveX, float mouseMoveY)
    {
      if (!this._initialized)
        return;
      this._panRotation += mouseMoveX * ((float) Math.PI / 720f);
      this._tiltRotation += mouseMoveY * ((float) Math.PI / 720f);
      this._tiltRotation = MathF.Clamp(this._tiltRotation, -2.984513f, -0.157079637f);
      MatrixFrame frame1 = this._itemTableauEntity.GetFrame();
      Vec3 vec3 = (this._itemTableauEntity.GetBoundingBoxMax() + this._itemTableauEntity.GetBoundingBoxMin()) * 0.5f;
      MatrixFrame identity1 = MatrixFrame.Identity with
      {
        origin = vec3
      };
      MatrixFrame identity2 = MatrixFrame.Identity with
      {
        origin = -vec3
      };
      MatrixFrame matrixFrame = (frame1 * identity1) with
      {
        rotation = Mat3.Identity
      };
      matrixFrame.rotation.ApplyScaleLocal(this._initialFrame.rotation.GetScaleVector());
      matrixFrame.rotation.RotateAboutSide(this._tiltRotation);
      matrixFrame.rotation.RotateAboutUp(this._panRotation);
      MatrixFrame frame2 = matrixFrame * identity2;
      this._itemTableauEntity.SetFrame(ref frame2);
    }

    public void SetInitialTiltRotation(float amount)
    {
      this._hasInitialTiltRotation = true;
      this._initialTiltRotation = amount;
    }

    public void SetInitialPanRotation(float amount)
    {
      this._hasInitialPanRotation = true;
      this._initialPanRotation = amount;
    }

    public void Zoom(double value) => this._curZoomSpeed -= (float) (value / 1000.0);

    public void SetItem(ItemRosterElement itemRosterElement)
    {
      this._itemRosterElement = itemRosterElement;
      this.RefreshItemTableau();
    }

    private void RefreshItemTableau()
    {
      if (!this._initialized)
        this.Initialize();
      if ((NativeObject) this._itemTableauEntity != (NativeObject) null)
      {
        this._itemTableauEntity.Remove(102);
        this._itemTableauEntity = (GameEntity) null;
      }
      EquipmentElement equipmentElement = this._itemRosterElement.EquipmentElement;
      if (equipmentElement.Item == null)
        return;
      equipmentElement = this._itemRosterElement.EquipmentElement;
      ItemObject.ItemTypeEnum itemType = equipmentElement.Item.ItemType;
      if ((NativeObject) this._itemTableauEntity == (NativeObject) null)
      {
        MatrixFrame frameForItemTooltip = this._itemRosterElement.GetItemFrameForItemTooltip();
        frameForItemTooltip.origin.z += 2.5f;
        MetaMesh meshForInventory = this._itemRosterElement.GetItemMeshForInventory();
        Banner banner = new Banner(this._bannerCode);
        uint num1 = 0;
        uint num2 = 0;
        if (!string.IsNullOrEmpty(this._bannerCode))
        {
          num1 = banner.GetPrimaryColor();
          BannerColor bannerColor;
          if (banner.BannerDataList.Count > 0 && BannerManager.ColorPalette.TryGetValue(banner.BannerDataList[1].ColorId, out bannerColor))
            num2 = bannerColor.Color;
        }
        if ((NativeObject) meshForInventory != (NativeObject) null)
        {
          if (itemType == ItemObject.ItemTypeEnum.HandArmor)
          {
            this._itemTableauEntity = GameEntity.CreateEmpty(this._tableauScene);
            AnimationSystemData animationSystemData = Game.Current.DefaultMonster.FillAnimationSystemData(MBActionSet.GetActionSet(Game.Current.DefaultMonster.ActionSetCode), 1f, false);
            this._itemTableauEntity.CreateSkeletonWithActionSet(ref animationSystemData);
            this._itemTableauEntity.SetFrame(ref frameForItemTooltip);
            this._itemTableauEntity.Skeleton.SetAgentActionChannel(0, ActionIndexCache.Create("act_tableau_hand_armor_pose"));
            this._itemTableauEntity.AddMultiMeshToSkeleton(meshForInventory);
            this._itemTableauEntity.Skeleton.TickActionChannels();
            this._itemTableauEntity.Skeleton.TickAnimationsAndForceUpdate(0.01f, frameForItemTooltip, true);
          }
          else if (itemType == ItemObject.ItemTypeEnum.Horse || itemType == ItemObject.ItemTypeEnum.Animal)
          {
            equipmentElement = this._itemRosterElement.EquipmentElement;
            HorseComponent horseComponent = equipmentElement.Item.HorseComponent;
            Monster monster = horseComponent.Monster;
            this._itemTableauEntity = GameEntity.CreateEmpty(this._tableauScene);
            MBActionSet actionSet = MBGlobals.GetActionSet(horseComponent.Monster.ActionSetCode);
            AnimationSystemData animationSystemData = monster.FillAnimationSystemData(actionSet, 1f, false);
            this._itemTableauEntity.CreateSkeletonWithActionSet(ref animationSystemData);
            this._itemTableauEntity.Skeleton.SetAgentActionChannel(0, ActionIndexCache.Create("act_inventory_idle_start"));
            this._itemTableauEntity.SetFrame(ref frameForItemTooltip);
            this._itemTableauEntity.AddMultiMeshToSkeleton(meshForInventory);
          }
          else
          {
            if (itemType == ItemObject.ItemTypeEnum.HorseHarness)
            {
              equipmentElement = this._itemRosterElement.EquipmentElement;
              if (equipmentElement.Item.ArmorComponent != null)
              {
                this._itemTableauEntity = this._tableauScene.AddItemEntity(ref frameForItemTooltip, meshForInventory);
                equipmentElement = this._itemRosterElement.EquipmentElement;
                MetaMesh copy = MetaMesh.GetCopy(equipmentElement.Item.ArmorComponent.ReinsMesh, mayReturnNull: true);
                if ((NativeObject) copy != (NativeObject) null)
                {
                  this._itemTableauEntity.AddMultiMesh(copy);
                  goto label_32;
                }
                else
                  goto label_32;
              }
            }
            if (itemType == ItemObject.ItemTypeEnum.Shield)
            {
              equipmentElement = this._itemRosterElement.EquipmentElement;
              if (equipmentElement.Item.IsUsingTableau && !banner.BannerDataList.IsEmpty<BannerData>())
              {
                MetaMesh metaMesh = meshForInventory;
                equipmentElement = this._itemRosterElement.EquipmentElement;
                Material tableauMaterial = equipmentElement.Item.GetTableauMaterial(banner);
                metaMesh.SetMaterial(tableauMaterial);
              }
              this._itemTableauEntity = this._tableauScene.AddItemEntity(ref frameForItemTooltip, meshForInventory);
            }
            else if (itemType == ItemObject.ItemTypeEnum.Banner)
            {
              equipmentElement = this._itemRosterElement.EquipmentElement;
              if (equipmentElement.Item.IsUsingTableau && !banner.BannerDataList.IsEmpty<BannerData>())
              {
                MetaMesh metaMesh = meshForInventory;
                equipmentElement = this._itemRosterElement.EquipmentElement;
                Material tableauMaterial = equipmentElement.Item.GetTableauMaterial(banner);
                metaMesh.SetMaterial(tableauMaterial);
              }
              if (!string.IsNullOrEmpty(this._bannerCode))
              {
                for (int meshIndex = 0; meshIndex < meshForInventory.MeshCount; ++meshIndex)
                {
                  meshForInventory.GetMeshAtIndex(meshIndex).Color = num1;
                  meshForInventory.GetMeshAtIndex(meshIndex).Color2 = num2;
                }
              }
              this._itemTableauEntity = this._tableauScene.AddItemEntity(ref frameForItemTooltip, meshForInventory);
            }
            else
              this._itemTableauEntity = this._tableauScene.AddItemEntity(ref frameForItemTooltip, meshForInventory);
          }
        }
        else
        {
          equipmentElement = this._itemRosterElement.EquipmentElement;
          MBDebug.ShowWarning("[DEBUG]Item with " + equipmentElement.Item.StringId + "[DEBUG] string id cannot be found");
        }
      }
label_32:
      SkinMask p1 = SkinMask.AllVisible;
      equipmentElement = this._itemRosterElement.EquipmentElement;
      if (equipmentElement.Item.HasArmorComponent)
      {
        equipmentElement = this._itemRosterElement.EquipmentElement;
        p1 = equipmentElement.Item.ArmorComponent.MeshesMask;
      }
      string metaMeshName = "";
      equipmentElement = this._itemRosterElement.EquipmentElement;
      bool flag1 = equipmentElement.Item.ItemFlags.HasAnyFlag<ItemFlags>(ItemFlags.NotUsableByMale);
      bool flag2 = false;
      if (ItemObject.ItemTypeEnum.HeadArmor == itemType || ItemObject.ItemTypeEnum.Cape == itemType)
      {
        metaMeshName = "base_head";
        flag2 = true;
      }
      else if (ItemObject.ItemTypeEnum.BodyArmor == itemType)
      {
        if (p1.HasAnyFlag<SkinMask>(SkinMask.BodyVisible))
        {
          metaMeshName = "base_body";
          flag2 = true;
        }
      }
      else if (ItemObject.ItemTypeEnum.LegArmor == itemType)
      {
        if (p1.HasAnyFlag<SkinMask>(SkinMask.LegsVisible))
        {
          metaMeshName = "base_foot";
          flag2 = true;
        }
      }
      else if (ItemObject.ItemTypeEnum.HandArmor == itemType)
      {
        if (p1.HasAnyFlag<SkinMask>(SkinMask.HandsVisible))
          this._itemTableauEntity.AddMultiMeshToSkeleton(MetaMesh.GetCopy(flag1 ? "base_hand_female" : "base_hand", false));
      }
      else if (ItemObject.ItemTypeEnum.HorseHarness == itemType)
      {
        metaMeshName = "horse_base_mesh";
        flag2 = false;
      }
      if (metaMeshName.Length > 0)
      {
        if (flag2 & flag1)
          metaMeshName += "_female";
        this._itemTableauEntity.AddMultiMesh(MetaMesh.GetCopy(metaMeshName, false));
      }
      TableauView view = this.View;
      if ((NativeObject) view != (NativeObject) null)
      {
        float radius = (this._itemTableauEntity.GetBoundingBoxMax() - this._itemTableauEntity.GetBoundingBoxMin()).Length * 2f;
        Vec3 origin = this._itemTableauEntity.GetGlobalFrame().origin;
        view.SetFocusedShadowmap(true, ref origin, radius);
      }
      if (!((NativeObject) this._itemTableauEntity != (NativeObject) null))
        return;
      this._initialFrame = this._itemTableauEntity.GetFrame();
      Vec3 eulerAngles = this._initialFrame.rotation.GetEulerAngles();
      this._panRotation = eulerAngles.x;
      this._tiltRotation = eulerAngles.z;
      if (this._hasInitialPanRotation)
        this._panRotation = this._initialPanRotation;
      else if (itemType == ItemObject.ItemTypeEnum.Shield)
        this._panRotation = -3.14159274f;
      if (this._hasInitialTiltRotation)
        this._tiltRotation = this._initialTiltRotation;
      else if (itemType == ItemObject.ItemTypeEnum.Shield)
        this._tiltRotation = 0.0f;
      else
        this._tiltRotation = -1.57079637f;
    }

    private void TableauMaterialTabInventoryItemTooltipOnRender(Texture sender, EventArgs e)
    {
      if (!this._initialized)
        return;
      TableauView tableauView = this.View;
      if ((NativeObject) tableauView == (NativeObject) null)
      {
        tableauView = sender.TableauView;
        tableauView.SetEnable(this._isEnabled);
      }
      if (this._itemRosterElement.EquipmentElement.Item == null)
      {
        tableauView.SetContinuousRendering(false);
        tableauView.SetDeleteAfterRendering(true);
      }
      else
      {
        tableauView.SetRenderWithPostfx(true);
        tableauView.SetClearColor(0U);
        tableauView.SetScene(this._tableauScene);
        if ((NativeObject) this._camera == (NativeObject) null)
        {
          this._camera = Camera.CreateCamera();
          this._camera.SetViewVolume(true, -0.5f, 0.5f, -0.5f, 0.5f, 0.01f, 100f);
          this.ResetCamera();
          tableauView.SetSceneUsesSkybox(false);
        }
        tableauView.SetCamera(this._camera);
        if (this._isRotatingByDefault)
          this.UpdateRotation(1f, 0.0f);
        tableauView.SetDeleteAfterRendering(false);
        tableauView.SetContinuousRendering(true);
      }
    }

    private void MakeCameraLookMidPoint()
    {
      this._camera.Position = this._midPoint + this._camera.Frame.rotation.TransformToParent(this._curCamDisplacement) - this._camera.Direction * (this._midPoint.Length * 0.5263158f);
    }

    private void SetCamFovHorizontal(float camFov)
    {
      this._camera.SetFovHorizontal(camFov, 1f, 0.1f, 50f);
    }

    private void UpdateMouseLock(bool forceUnlock = false)
    {
      this._lockMouse = (this._isRotating || this._isTranslating) && !forceUnlock;
      MouseManager.LockCursorAtCurrentPosition(this._lockMouse);
      MouseManager.ShowCursor(!this._lockMouse);
    }

    private void TickCameraZoom(float dt)
    {
      if (!((NativeObject) this._camera != (NativeObject) null))
        return;
      this.SetCamFovHorizontal(MBMath.ClampFloat(this._camera.HorizontalFov + this._curZoomSpeed, 0.1f, 2f));
      if ((double) dt <= 0.0)
        return;
      this._curZoomSpeed = MBMath.Lerp(this._curZoomSpeed, 0.0f, MBMath.ClampFloat(dt * 25.9f, 0.0f, 1f));
    }
  }
}
